# 原Java算法以及启发 来自GangJust大神 https://gitee.com/GangJust/kingosoft_api
# 由 e1chan 移植到Python
import hashlib
import math
import urllib.parse
import http.client
import json
import time
import sys


def parseint(string):
    stri = ''
    for x in string:
        if x.isdigit():
            stri += x
        else:
            break
    return int(stri)


def encrypt_md5(s):
    # 创建md5对象
    new_md5 = hashlib.md5()
    # 这里必须用encode()函数对字符串进行编码，不然会报 TypeError: Unicode-objects must be encoded before hashing
    new_md5.update(s.encode(encoding='utf-8'))
    # 加密
    return new_md5.hexdigest()


class Info:
    appVer = 'android2.5.101'
    encodeKey = 'op5nb9'
    schoolCode = '10298'  # 默认为10298南京林业大学
    phoneModel = 'Redmi K20 Pro'
    os = 'android'
    osVersion = '10'
    loginId = ''
    password = ''
    isRun = 0
    isLogin = 0
    host = "www.xiqueer.com"
    send_url = "/manager/wap/wapController.jsp"
    web_send_url = "/manager/wap/jwApi.jsp"
    headers = {'Content-type': 'application/x-www-form-urlencoded', 'Accept': 'text/plain'}
    conn = ''


class ParamUtil:
    def getLoginParams(self, schoolCode, phoneModel, os, osVersion, loginId, password):
        phoneModel = "MI 8" if phoneModel is None or phoneModel.strip() == "" else phoneModel
        os = "android" if os is None or os.strip() == "" else os
        osVersion = "10" if osVersion is None or osVersion.strip() == "" else osVersion

        if schoolCode is None or schoolCode.strip() == "":
            return None
        if loginId is None or loginId.strip() == "":
            return None
        if password is None or password.strip() == "":
            return None

        buffer = ""
        buffer += "xxdm=" + schoolCode + "&"
        buffer += "sjxh=" + phoneModel + "&"
        buffer += "loginId=" + loginId + "&"
        buffer += "sswl=" + "55555" + "&"
        buffer += "os=" + os + "&"
        buffer += "xtbb=" + osVersion + "&"
        buffer += "appver=" + Info.appVer + "&"
        buffer += "action=" + "getLoginInfoNew" + "&"
        buffer += "isky=" + "1" + "&"
        buffer += "sjbz=" + "" + "&"
        buffer += "pwd=" + password + "&"
        buffer += "loginmode=" + "0"

        return buffer

    def getCourseParams(self, jsdm, bjdm, week, xnxq, userJSON):
        jsdm = "" if jsdm is None or jsdm.strip() == "" else jsdm
        bjdm = "" if bjdm is None or bjdm.strip() == "" else bjdm
        if week is None or week.strip() == "":
            return None
        if xnxq is None or xnxq.strip() == "":
            return None
        if userJSON is None:
            return None
        buffer = ''
        buffer += "jsdm=" + jsdm + "&"
        buffer += "week=" + week + "&"
        buffer += "xnxq=" + xnxq + "&"
        buffer += "channel=" + "jrkb" + "&"
        buffer += "usertype=" + userJSON["usertype"] + "&"
        buffer += "action=" + "getKb" + "&"
        buffer += "step=" + "kbdetail_bz" + "&"
        buffer += "userId=" + userJSON['userid'] + "&"
        buffer += "bjdm=" + bjdm + "&"
        buffer += "sfid=" + userJSON['userid'] + "&"
        buffer += "uuid=" + userJSON['uuid']
        return buffer


class Encoding:
    def __init__(self):
        self.map = dict()

    def webEncodeing(self, stri, str2):
        try:
            return "param=" + self.getParamEncode(stri, str2) + "&param2=" + self.getParam2Encode(stri)
        except BaseException:
            return "param=error&param2=error"

    def getParamEncode(self, stri, s):
        if stri is None or "" == stri or s is None or "" == s:
            return stri
        s2 = ""
        length = len(s)
        length2 = len(stri)
        n = math.ceil(length2 * 1.0 / length)
        n2 = math.ceil(length2 * 3.0 * 6.0 / 9.0 / 6.0)
        string2 = ""
        for i in range(0, n):
            n3 = 1
            while True:
                s3 = string2
                if n3 > length:
                    break
                n4 = i * length + n3
                string3 = "000" + str(
                    parseint(self.toArray(stri[n4 - 1: n4])) + parseint(self.toArray(s[n3 - 1: n3])) + n2 * 6 % length)
                string2 += string3[len(string3) - 3:]
                if n4 == length2:
                    s3 = string2
                    break
                n3 += 1
            string2 = s3
            i += 1

        n5 = 0
        stri = s2
        while True:
            s = stri
            if n5 >= len(string2):
                break
            length3 = n5 + 9
            if length3 >= len(string2):
                length3 = len(string2)
            s = string2[n5: length3]
            n5 += 9
            s = "000000" + self.a(int(s))
            s = s[len(s) - 6:]
            stri += s
        return s

    def getParam2Encode(self, stri):
        split = list(str(encrypt_md5(stri)))
        if not ("" == split[0].strip()):
            tmp = dict()
            tmp[0] = ""
            for i in range(0, len(split)):
                tmp[i + 1] = split[i]
                i += 1
            split = tmp
        str2 = ""
        for i in range(0, len(split)):
            if not (i == 3 or i == 10 or i == 17 or i == 25):
                str2 = str2 + split[i]
            i += 1
        md5 = encrypt_md5(str2)
        return md5

    def putMap(self):
        i = 0
        if self.map is None:
            self.map = dict()
        for i2 in range(0, 10):
            self.map[i2] = chr(i2 + 48)
            i2 += 1
        while i < 26:
            self.map[i + 10] = chr(i + 97)
            i += 1

    def toArray(self, s):
        sb = ""
        charArray = list(s)
        for i in range(0, len(charArray)):
            if i != len(charArray) - 1:
                sb += str(ord(s[i])) + ","
            else:
                sb += str(ord(s[i]))
            i += 1
        return sb

    def a(self, j):
        self.putMap()
        stri = ''
        if j < 0:
            return "-" + self.a(abs(j))
        while True:
            str2 = stri
            key = math.floor(j % 36)
            stri = str(self.map.get(key)) + ''
            if not ("" == str2):
                stri = stri + str2
            j = math.floor(j / 36)
            if j <= 0:
                break
        return stri


class EncodeUtil:
    def encode(self, stri, bool, userId, uuid, token):
        key = Info.encodeKey
        if bool:
            stri = stri + "&sfid=" + userId + "&uuid=" + uuid
        if stri.find("&") == 0:
            stri = stri[1:]
        hashMap = dict()
        # try:
        hashMap["param"] = Encoding().getParamEncode(stri, key)
        hashMap["param2"] = Encoding().getParam2Encode(stri)
        hashMap["token"] = token
        hashMap["appinfo"] = Info.appVer

        return hashMap

    def encoding(self, params, token):
        token = "00000" if token.strip() == "" else token
        hashMap = EncodeUtil().encode(params, False, "", "", token)
        hashMap["token"] = token
        return hashMap

    def webEncoding(self, userJSON, type, step):
        buffer = ''
        buffer += "user=" + userJSON['userid'] + "&"
        buffer += "usertype=" + userJSON['usertype'] + "&"
        buffer += "uuid=" + userJSON['uuid']
        encode1 = Encoding().webEncodeing(buffer, userJSON['xxdm'])
        encode1 = encode1 + "&xxdm=" + userJSON['xxdm']
        encode2 = Encoding().webEncodeing(encode1, Info.encodeKey)
        buffer1 = ''
        buffer1 += (urllib.parse.quote("head[us]")) + "=&"
        buffer1 += (urllib.parse.quote("head[version]")) + '=' + "1.0.0" + "&"
        buffer1 += (urllib.parse.quote("head[ct]")) + '=' + "3" + "&"
        buffer1 += (urllib.parse.quote("head[time]")) + '=' + (str(time.time()))[0: 10] + "&"
        buffer1 += (urllib.parse.quote("head[sign]")) + '=' + "&"
        buffer1 += "sign=" + (urllib.parse.quote(encode2)) + (urllib.parse.quote("&token=")) + \
                   (userJSON['token']) + (urllib.parse.quote("&appinfo=")) + Info.appVer + "&"
        buffer1 += "action=" + "jw_apply" + "&"
        buffer1 += "type=" + type + "&"
        buffer1 += "step=" + step
        return buffer1


userJson = dict()


def postData(maps):
    params = urllib.parse.urlencode(maps)
    # print("发送参数：%s" % params)
    Info.conn = http.client.HTTPConnection(Info.host, port=8080, timeout=30)
    Info.conn.request('POST', Info.send_url, params, Info.headers)
    response = Info.conn.getresponse()
    response_str = response.read()
    jsonstr = response_str.decode('utf-8')
    if jsonstr == '':
        print("没有返回值，有可能是因为参数不正确")
        return -1
    json_return = json.loads(jsonstr)
    return json_return

def postWebApi(params):
    Info.conn = http.client.HTTPConnection(Info.host, port=8080, timeout=30)
    Info.conn.request('POST', Info.web_send_url, params, Info.headers)
    response = Info.conn.getresponse()
    response_str = response.read()
    jsonstr = response_str.decode('utf-8')
    if jsonstr == '':
        print("WebApi没有返回值，有可能是因为参数不正确")
        return -1
    json_return = json.loads(jsonstr)
    return json_return


def login():
    if Info.loginId == '' or Info.password == '':
        print('请先设置用户名和密码')
        return -1
    else:
        loginParams1 = ParamUtil().getLoginParams(Info.schoolCode, Info.phoneModel, Info.os, Info.osVersion,
                                                  Info.loginId, Info.password)
        map1 = EncodeUtil().encoding(loginParams1, '00000')
        # print(loginParams1)
        # print(map1)
        global userJson
        userJson = postData(map1)
        if userJson == -1:
            print("登录失败，无返回，有可能因为参数错误")
            sys.exit(1)
        else:
            if userJson['msg'] == '通过身份验证！':
                print("登录成功")
                print(userJson)
                print("姓名：%s" % userJson['xm'])
                print("教务版本：%s" % userJson['jw'])
                print("用户ID：%s" % userJson['userid'])
            else:
                print(userJson['msg'])
        Info.conn.close()
        return userJson


def getCourse(jsdm, bjdm, week, xnxq):
    """
    查询周课表

    :param jsdm: (str)教室代码
    :param bjdm: (str)班级代码
    :param week: (str)周次，例如：'7'
    :param xnxq: (str)学年学期，例如'20190'
    :return: 返回包含该周课表的JSON字典
    """
    global userJson
    if userJson['msg'] != '通过身份验证！':
        print("由于没有通过身份验证，无法获取课程信息")
        return -1
    courseParams = ParamUtil().getCourseParams(jsdm, bjdm, week, xnxq, userJson)
    # print(courseParams)
    courseMap = EncodeUtil().encoding(courseParams, userJson['token'])
    # print(courseMap)
    resStr = postData(courseMap)
    if resStr == '':
        print("查询课表失败，有可能是因为参数不正确")
        return -1
    else:
        return resStr


def getGrowPlan():
    global userJson
    if userJson['msg'] != '通过身份验证！':
        print("由于没有通过身份验证，无法获取培养方案")
        return -1
    growMap = EncodeUtil().webEncoding(userJson, 'pyfa', 'list')
    resStr = postWebApi(growMap)
    if resStr == '':
        print("查询培养方案失败，有可能是因为参数不正确")
        return -1
    else:
        return resStr
